package org.strieber.fca.mid3;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.strieber.fca.Rule;

public class MID3 extends ID3 {

	public MID3() {
		
	}
	
	public MID3(HashMap<String, List<String>> domains, ArrayList<Rule> rules) {
		this.domains = domains;
		this.rules = rules;
		String highestGainAttribute = findHighestGain(this.rules);
		DecisionNode node = new DecisionNode();
		node.setRules(rules);
		node.setEntropy(calculateMainEntropy());
		System.out.println("dataset entropy: " + calculateMainEntropy());
		node.setAttributeSplitOn(highestGainAttribute);
		root = node;
		// expand on the root node
		expandNode(root);
	}
	
	protected void expandNode(DecisionNode node) {
		// grab the node we are working on
		DecisionNode currentNode = node;
		// all nodes must have the dollar branch
		DecisionNode dollarNode = new DecisionNode();		
		// get all the rules from that node
		List<Rule> nodeRules = currentNode.getRules();
		// find the attribute the currentNode will be split on
		String attributeSplitOn = currentNode.getAttributeSplitOn();
		// create a list that holds the rules that have no matching
		// attribute
		List<Rule> dollarRules = new ArrayList<Rule>();
		// go through the rule set, if there are any rules
		// that do not have a value for the attribute to
		// split on, place it in the dollarBranch
		for (int i = nodeRules.size() - 1; i >= 0; i++) {
			Rule currentRule = nodeRules.get(i);
			if (!currentRule.matchesIntent(attributeSplitOn)) {
				nodeRules.remove(i);
				dollarRules.add(currentRule);
			}
		}
		// set the dollar node's rules to the rules that didn't match
		dollarNode.setRules(dollarRules);
		// add the dollar node to the current node
		currentNode.addChild(dollarNode);
		// if the rule list is empty or if all the intents are the same, skip it
		if ((nodeRules.size() != 0) && !allSameDetermined(nodeRules)) {
			// get all the possible values for that attribute
			List<String> attributeValues = domains.get(attributeSplitOn);
			// add the attribute to the list of used attributes
			usedAttributes.add(attributeSplitOn);
			for (int i = 0; i < attributeValues.size(); i++) {
				// select one of the possible attribute values
				String currentAttributeValue = attributeValues.get(i);
				// find all the matching rules of that attribute/value pair
				List<Rule> matchingRules = findMatchingRules(attributeSplitOn, currentAttributeValue, nodeRules);
				
				if (matchingRules.size() > 0) {
					// create a new child node to attach to the current node
					DecisionNode childNode = new DecisionNode();
					// set the rules of the child as the matching rules
					childNode.setRules(matchingRules);
					// find the next highest gain attribute
					String highestGainAttribute = findHighestGain(matchingRules);
					// set the child node's highest gain attribute
					childNode.setAttributeSplitOn(highestGainAttribute);
					// set the child's value split on
					childNode.setValueSplitOn(currentAttributeValue);
					// set the child's entropy
					childNode.setEntropy(calculateEntropy(matchingRules));
					// set the child's parent
					childNode.setParent(currentNode);
					// add the child to the parent
					currentNode.addChild(childNode);
				}			
			}
			// expand all of the current node's new children
			for (int j = 0; j < currentNode.getChildren().size(); j++) {
				expandNode(currentNode.getChildren().get(j));
			}
		}
	}
	
	public static void main(String[] args) {
		// setup domains
		HashMap<String, List<String>> domains = new HashMap<String, List<String>>();
		ArrayList<String> values = new ArrayList<String>();
		
		values.add("1");
		values.add("2");
		domains.put("G", values);
		
		values = new ArrayList<String>();
		values.add("1");
		values.add("2");
		domains.put("CH", values);
		
		values = new ArrayList<String>();
		values.add("1");
		domains.put("ET", values);
		
		values = new ArrayList<String>();
		values.add("1");
		domains.put("MS", values);
		
		values = new ArrayList<String>();
		values.add("1");
		values.add("2");
		values.add("3");
		values.add("4");
		domains.put("MLR", values);
		
		values = new ArrayList<String>();
		values.add("7");
		values.add("8");
		values.add("9");
		domains.put("PCY", values);
		
		values = new ArrayList<String>();
		values.add("4");
		values.add("5");
		values.add("6");
		domains.put("PS", values);
		
		values = new ArrayList<String>();
		values.add("0");
		values.add("1");
		domains.put("T", values);
		
		ArrayList<Rule> rules = new ArrayList<Rule>();
		ArrayList<String> extents = new ArrayList<String>();
		ArrayList<String> intents = new ArrayList<String>();
		
		Rule tempRule = new Rule();
		
		double support;
		double confidence;
		
		// object 1
		extents.add("G=1");
		extents.add("MS=1");
		extents.add("MLR=1");
		extents.add("PS=4");
		intents.add("T=0");
		support = 20;
		confidence = 60;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// object 2
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();
		extents.add("CH=2");
		extents.add("G=2");
		extents.add("MLR=3");
		extents.add("PCY=9");
		intents.add("T=1");
		support = 20;
		confidence = 70;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// object 3
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();
		extents.add("ET=1");
		extents.add("MS=1");
		extents.add("MLR=2");
		extents.add("PCY=8");
		intents.add("T=0");
		support = 30;
		confidence = 100;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// object 4
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();
		extents.add("CH=2");
		extents.add("ET=1");
		extents.add("MLR=2");
		extents.add("PCY=9");
		intents.add("T=0");
		support = 30;
		confidence = 90;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// object 5
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();
		extents.add("G=1");
		extents.add("MS=1");
		extents.add("MLR=3");
		extents.add("PS=5");
		intents.add("T=1");
		support = 20;
		confidence = 80;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// object 6
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();
		extents.add("ET=1");
		extents.add("G=1");
		extents.add("MLR=4");
		extents.add("PS=6");
		intents.add("T=0");
		support = 20;
		confidence = 100;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// object 7
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();
		extents.add("CH=2");
		extents.add("ET=1");
		extents.add("PCY=9");
		extents.add("PS=5");
		intents.add("T=0");
		support = 20;
		confidence = 80;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// object 8
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();		
		extents.add("CH=2");
		extents.add("G=1");
		extents.add("MLR=3");
		extents.add("PS=6");
		intents.add("T=1");
		support = 20;
		confidence = 60;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// object 9
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();		
		extents.add("CH=2");
		extents.add("MS=1");
		extents.add("MLR=3");
		extents.add("PS=6");
		intents.add("T=1");
		support = 20;
		confidence = 70;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);

		// object 10
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();		
		extents.add("ET=1");
		extents.add("G=1");
		extents.add("PCY=8");
		extents.add("PS=4");
		intents.add("T=0");
		support = 30;
		confidence = 90;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);

		// object 11
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();		
		extents.add("CH=1");
		extents.add("G=1");
		extents.add("MLR=3");
		extents.add("PCY=7");
		intents.add("T=1");
		support = 20;
		confidence = 80;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);

		// object 12
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();		
		extents.add("ET=1");
		extents.add("G=1");
		extents.add("MLR=3");
		extents.add("PS=5");
		intents.add("T=0");
		support = 40;
		confidence = 80;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);

		// object 13
		extents = new ArrayList<String>();
		intents = new ArrayList<String>();		
		extents.add("ET=1");
		extents.add("MS=1");
		extents.add("PCY=9");
		extents.add("PS=6");
		intents.add("T=0");
		support = 20;
		confidence = 100;
		tempRule = new Rule(extents, intents, support, confidence);
		rules.add(tempRule);
		
		// create id3 object
		MID3 mid3 = new MID3(domains, rules);
		System.out.println(mid3);
	}
}
